﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Farigola.Engine.SystemData;
using Farigola.Engine.Factories;
using Farigola.Engine.SystemData.Entity.Type;
using Farigola.Engine.Reposit;

namespace Farigola.Engine
{
    /// <summary>
    /// A workspace is a main object and unique in the engine core application.
    /// Its the main area (in memory) to manage projects.
    /// Only one main/current project is running in the workspace.
    /// but a workspace can access others dependent projects used/referenced by the main one.
    ///  
    /// It is not saved/persisted, only projects are saved/persisted.
    /// 
    /// The workspace manage all types and data types and data (the framework)
    /// 
    /// </summary>
    public class Workspace
    {
        /// <summary>
        /// The factory to build all object: workspace, project, and all
        ///  domain objects of the application.
        /// </summary>
        private Factory _factory;

        /// <summary>
        /// Manager tasks activity in the application (trace)
        /// Manage alos errors occurs in the engine.
        /// </summary>
        private AppActivityMgr _appActivityMgr;

        /**
         * manager of all system data: 
         * built-in types and instances (entities,...).
         */
        private SystemDataMgr _systemDataMgr;

        /// <summary>
        /// The project repository, to persist project content.
        /// </summary>
        private IProjectReposit _projectReposit;

        //---------------------------------------------------------------------
        /// <summary>
        /// The active project, only one.
        /// </summary>
        private Project _activeProject;

        // others projects, if needed.
        // todo:

        //---------------------------------------------------------------------
        /// <summary>
        /// Constructor.
        /// </summary>
        public Workspace(Factory factory, AppActivityMgr appActivityMgr)
        {
            //_factory = Factory.GetFactory();
            _factory = factory;

            _appActivityMgr = appActivityMgr;

            // create the (unique and central) system data manager
            _systemDataMgr = _factory.CreateSystemDataMgr();
        }

        //---------------------------------------------------------------------
        public void SetProjectReposit(IProjectReposit projectReposit)
        {
            _projectReposit = projectReposit;

            // provide the factory, need to build objects
            _projectReposit.SetFactory(_factory);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// check the workspace internal content, after init.
        /// a basic check, if an error occurs, return false.
        /// </summary>
        /// <returns></returns>
        public bool CheckInternal()
        {
            if (_appActivityMgr == null)
                return false;

            if (_factory == null)
                return false;

            if (_systemDataMgr == null)
                return false;

            return _systemDataMgr.CheckInternal();
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// init the workspace.
        /// init builtin type and data manager.
        /// </summary>
        /// <returns></returns>
        public bool Init()
        {
            if (_factory == null)
                return false;

            if (_appActivityMgr == null)
                return false;

            // init the manager of builtin types
            _systemDataMgr.Init();

            // create all system built-in objects: types and data
            _factory.CreateAllBuiltInSystemData(_systemDataMgr);

            // error?
            // todo:

            // ok the init is done
            return true;
        }

        //=====================================================================
        #region Get/Set methods.

        //---------------------------------------------------------------------
        public SystemDataMgr GetSystemDataMgr()
        {
            return _systemDataMgr;

        }
        //---------------------------------------------------------------------
        /// <summary>
        /// return the active poject of the workspace.
        /// </summary>
        /// <returns></returns>
        public Project GetActiveProject()
        {
            return _activeProject;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// get the last error occurs in the engine.
        /// </summary>
        /// <returns></returns>
        public AppError GetLastError()
        {
            return _appActivityMgr.GetLastError();
        }

        #endregion


        //---------------------------------------------------------------------
        /// <summary>
        /// Find an ent type by the name.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public EntTypeBase FindEntTypeBaseByName(string name)
        {
            return GetSystemDataMgr().FindEntTypeByName(name);
        }


        //=====================================================================
        #region Project methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Create a project in the current workspace,
        /// becomes the active project.
        /// 
        /// if an active project is already present, must remove it. 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public Project CreateActiveProject(String name)
        {
            // an active project is already present?
            if (_activeProject != null)
                return null;

            // save the created projects, becomes the active one
            _activeProject = _factory.CreateProject(name);
            return _activeProject;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// save the active project.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public bool SaveActiveProject(string fileName)
        {
            // start a new task, clear the current error
            _appActivityMgr.StartTask(EngineDef.ActionCode.SaveActiveProject.ToString());

            // an active project is not present?
            if (_activeProject == null)
                return _appActivityMgr.AddErrorRetFalse(EngineDef.ErrorCode.ActiveProjectIsNull.ToString());

            if(_projectReposit == null)
                return false;

            // save, the concrete reposit will check the name
            if (!_projectReposit.SaveProject(_activeProject, fileName))
                return false;

            // task ends ok
            return _appActivityMgr.StopTaskOk();
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// load a saved project, becomes the active project.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public Project LoadActiveProject(string fileName)
        {
            // start a new action, clear the current error
            _appActivityMgr.StartTask(EngineDef.ActionCode.LoadActiveProject.ToString());

            // an active project is already present?
            if (_activeProject != null)
            {
                _appActivityMgr.AddErrorRetFalse(EngineDef.ErrorCode.ActiveProjectIsPresent.ToString());
                return null;
            }

            // load, the concrete reposit will check the name
            if (!_projectReposit.LoadProject(fileName, out _activeProject))
                return null;

            // task ends ok
            _appActivityMgr.StopTaskOk();

            return _activeProject;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// close (remove from the workspace) the active project.
        /// </summary>
        /// <returns></returns>
        public bool CloseActiveProject()
        {
            // an active project is not present?
            if (_activeProject == null)
                return false;

            // check if the project is updated?
            // todo:

            //_activeProject.Close();

            _activeProject = null;
            return true;
        }

        #endregion


    }
}
